#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
EasyFTP - 客户端实现
v1.0版本
"""

import os
import json
import logging
import argparse
import ftplib
import time


class FtpClient:
    """FTP客户端类，负责连接FTP服务器并执行文件传输操作"""

    def __init__(self, config_file='../config/config.json'):
        """初始化FTP客户端配置"""
        # 加载配置文件
        self.config = self._load_config(config_file)
        # 设置日志
        self._setup_logging()
        # FTP连接实例
        self.ftp = None

    def _load_config(self, config_file):
        """加载配置文件"""
        try:
            with open(config_file, 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            print(f"加载配置文件失败: {e}")
            # 返回默认配置
            return {
                "client": {
                    "default_host": "127.0.0.1",
                    "default_port": 2121
                }
            }

    def _setup_logging(self):
        """设置日志配置"""
        log_level = getattr(logging, self.config.get("logging", {}).get("level", "INFO").upper(), logging.INFO)
        log_file = self.config.get("logging", {}).get("file", "ftp_client.log")
        
        logging.basicConfig(
            level=log_level,
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler(log_file)
                # 移除StreamHandler以避免与main.py的日志输出重复
            ]
        )
        self.logger = logging.getLogger("FTPClient")

    def connect(self, host=None, port=None, device_id=None, device_code=None):
        """连接到FTP服务器"""
        try:
            # 使用传入的参数或配置文件中的默认值
            host = host or self.config["client"]["default_host"]
            port = port or self.config["client"]["default_port"]
            
            # 创建FTP连接
            self.ftp = ftplib.FTP()
            self.logger.info(f"正在连接到FTP服务器: {host}:{port}")
            self.ftp.connect(host, port)
            
            # 使用设备ID和设备验证码登录
            if device_id and device_code:
                self.ftp.login(device_id, device_code)
                self.logger.info(f"登录成功: 设备ID={device_id}")
            else:
                self.logger.error("连接失败: 缺少设备ID或设备验证码")
                self.ftp = None
                return False
            
            # 进入被动模式
            self.ftp.set_pasv(True)
            self.logger.info("已进入被动模式")
            
            return True
        except Exception as e:
            error_msg = str(e)
            if '530' in error_msg:
                self.logger.error(f"连接失败: 设备ID或设备验证码错误")
                print("连接失败: 请检查设备ID和设备验证码是否正确")
            else:
                self.logger.error(f"连接失败: {e}")
            self.ftp = None
            return False

    def disconnect(self):
        """断开与FTP服务器的连接"""
        if self.ftp:
            try:
                self.ftp.quit()
                self.logger.info("已断开与服务器的连接")
            except:
                self.ftp.close()
                self.logger.info("已强制关闭连接")
            finally:
                self.ftp = None

    def list_files(self, path='.'):
        """列出服务器上的文件和目录"""
        if not self.ftp:
            self.logger.error("未连接到服务器")
            return None
        
        try:
            files = []
            self.ftp.cwd(path)
            self.ftp.dir(files.append)
            
            # 解析文件列表
            result = []
            for line in files:
                result.append(line)
                print(line)
            
            self.logger.info(f"列出目录 {path} 成功，共 {len(result)} 个条目")
            return result
        except Exception as e:
            self.logger.error(f"列出文件失败: {e}")
            return None

    def upload_file(self, local_file, remote_file=None):
        """上传文件到服务器"""
        if not self.ftp:
            self.logger.error("未连接到服务器")
            return False
        
        try:
            # 如果未指定远程文件名，则使用本地文件名
            if not remote_file:
                remote_file = os.path.basename(local_file)
            
            # 检查本地文件是否存在
            if not os.path.isfile(local_file):
                self.logger.error(f"本地文件不存在: {local_file}")
                return False
            
            # 获取文件大小
            file_size = os.path.getsize(local_file)
            self.logger.info(f"开始上传文件: {local_file} -> {remote_file}, 大小: {file_size} 字节")
            
            # 上传文件
            start_time = time.time()
            with open(local_file, 'rb') as f:
                self.ftp.storbinary(f'STOR {remote_file}', f)
            
            end_time = time.time()
            speed = file_size / (end_time - start_time) if (end_time - start_time) > 0 else 0
            
            self.logger.info(f"文件上传成功: {local_file} -> {remote_file}")
            self.logger.info(f"传输时间: {end_time - start_time:.2f} 秒, 传输速度: {speed/1024:.2f} KB/s")
            return True
        except Exception as e:
            self.logger.error(f"文件上传失败: {e}")
            return False

    def download_file(self, remote_file, local_file=None):
        """从服务器下载文件"""
        if not self.ftp:
            self.logger.error("未连接到服务器")
            return False
        
        try:
            # 如果未指定本地文件名，则保存到shared目录下
            if not local_file:
                # 获取当前脚本所在目录
                current_dir = os.path.dirname(os.path.abspath(__file__))
                # 构建shared目录路径
                shared_dir = os.path.join(current_dir, 'shared')
                # 确保shared目录存在
                if not os.path.exists(shared_dir):
                    os.makedirs(shared_dir)
                    self.logger.info(f"创建shared目录: {shared_dir}")
                # 构建完整的本地文件路径
                local_file = os.path.join(shared_dir, os.path.basename(remote_file))
            
            # 下载文件
            self.logger.info(f"开始下载文件: {remote_file} -> {local_file}")
            
            start_time = time.time()
            with open(local_file, 'wb') as f:
                self.ftp.retrbinary(f'RETR {remote_file}', f.write)
            
            end_time = time.time()
            file_size = os.path.getsize(local_file)
            speed = file_size / (end_time - start_time) if (end_time - start_time) > 0 else 0
            
            self.logger.info(f"文件下载成功: {remote_file} -> {local_file}")
            self.logger.info(f"传输时间: {end_time - start_time:.2f} 秒, 传输速度: {speed/1024:.2f} KB/s")
            return True
        except Exception as e:
            self.logger.error(f"文件下载失败: {e}")
            # 如果下载失败，删除可能部分下载的文件
            if os.path.exists(local_file):
                os.remove(local_file)
            return False

    def create_directory(self, dir_name):
        """在服务器上创建目录"""
        if not self.ftp:
            self.logger.error("未连接到服务器")
            return False
        
        try:
            self.ftp.mkd(dir_name)
            self.logger.info(f"创建目录成功: {dir_name}")
            return True
        except Exception as e:
            self.logger.error(f"创建目录失败: {e}")
            return False

    def delete_directory(self, dir_name):
        """在服务器上删除目录"""
        if not self.ftp:
            self.logger.error("未连接到服务器")
            return False
        
        try:
            self.ftp.rmd(dir_name)
            self.logger.info(f"删除目录成功: {dir_name}")
            return True
        except Exception as e:
            self.logger.error(f"删除目录失败: {e}")
            return False


def main():
    """主函数"""
    # 解析命令行参数
    parser = argparse.ArgumentParser(description='双向FTP文件传输系统 - 客户端')
    parser.add_argument('-c', '--config', default='../config/config.json', help='配置文件路径')
    parser.add_argument('-H', '--host', help='服务器IP地址')
    parser.add_argument('-P', '--port', type=int, help='服务器端口')
    parser.add_argument('-d', '--device-id', help='设备ID')
    parser.add_argument('-k', '--device-code', help='设备验证码')
    
    # 子命令
    subparsers = parser.add_subparsers(dest='command', help='命令')
    
    # list命令
    list_parser = subparsers.add_parser('list', help='列出服务器上的文件')
    list_parser.add_argument('path', nargs='?', default='.', help='目录路径')
    
    # upload命令
    upload_parser = subparsers.add_parser('upload', help='上传文件')
    upload_parser.add_argument('local_file', help='本地文件路径')
    upload_parser.add_argument('remote_file', nargs='?', help='远程文件路径')
    
    # download命令
    download_parser = subparsers.add_parser('download', help='下载文件')
    download_parser.add_argument('remote_file', help='远程文件路径')
    download_parser.add_argument('local_file', nargs='?', help='本地文件路径')
    
    # mkdir命令
    mkdir_parser = subparsers.add_parser('mkdir', help='创建目录')
    mkdir_parser.add_argument('dir_name', help='目录名称')
    
    # rmdir命令
    rmdir_parser = subparsers.add_parser('rmdir', help='删除目录')
    rmdir_parser.add_argument('dir_name', help='目录名称')
    
    args = parser.parse_args()
    
    # 创建客户端实例
    ftp_client = FtpClient(args.config)
    
    try:
        # 连接服务器
        if not ftp_client.connect(args.host, args.port, args.device_id, args.device_code):
            print("连接服务器失败，程序退出")
            return
        
        # 执行命令
        if args.command == 'list':
            ftp_client.list_files(args.path)
        elif args.command == 'upload':
            ftp_client.upload_file(args.local_file, args.remote_file)
        elif args.command == 'download':
            ftp_client.download_file(args.remote_file, args.local_file)
        elif args.command == 'mkdir':
            ftp_client.create_directory(args.dir_name)
        elif args.command == 'rmdir':
            ftp_client.delete_directory(args.dir_name)
        else:
            parser.print_help()
        
    finally:
        # 断开连接
        ftp_client.disconnect()


if __name__ == '__main__':
    main()